export class Text {
    constructor(canvas) {
        this.canvas = canvas;
        this.gl = getWebGLContext(this.canvas);
        this.canvasWidth = this.canvas.offsetWidth;
        this.canvasHeight = this.canvas.offsetHeight;
        this.ctx = document.createElement('canvas').getContext('2d');
        // document.body.appendChild(this.ctx.canvas);
        this._webglScript(this.gl);
        this.u_Sampler = this.gl.getUniformLocation(this.gl.program, 'u_Sampler');
        this.a_TexCoord = this.gl.getAttribLocation(this.gl.program, 'a_TexCoord');
    }

    _webglScript(gl) {
        let VSHADER_SOURCE =
            `attribute vec4 a_Position;
       attribute vec2 a_TexCoord;
       varying vec2 v_TexCoord;
       void main() {
          gl_Position = a_Position;
          v_TexCoord = a_TexCoord;
      }`;
        let FSHADER_SOURCE =
            `#ifdef GL_ES
       precision mediump float;
       #endif
       uniform sampler2D u_Sampler;
       varying vec2 v_TexCoord;
       void main() {
         gl_FragColor = texture2D(u_Sampler, v_TexCoord);
       }`;

        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
            console.log('Failed to initialize shaders');
            return;
        }
    }

    _drawTexture(text, fontSize = 0, lineWidth, color = '#ff0000') {
        const getPowerOfTwoForTextCanvas = value => {
            let pow = 1;
            while (pow < value) {
                pow = pow * 2;
            }
            return pow;
        };
        let textCanvasWidth = getPowerOfTwoForTextCanvas(lineWidth);
        this.ctx.canvas.width = textCanvasWidth;
        let lineWordNumber = Math.floor(textCanvasWidth / fontSize);
        let textCanvasHeight = getPowerOfTwoForTextCanvas(Math.ceil(text.length / lineWordNumber) * fontSize);
        this.ctx.canvas.height = textCanvasHeight;
        this.ctx.font = '900 '+ fontSize + 'px monospace';
        this.ctx.fillStyle = color;

        let lineHeight = fontSize;
        let wordsLength = 0;
        for (let i = 0, length = text.length; i < length; i++) {
            let tempWidth = this.ctx.measureText(text.substring(i, i + 1)).width;
            this.ctx.fillText(text.substring(i, i + 1), wordsLength, lineHeight);
            wordsLength += tempWidth;
            if (wordsLength >= textCanvasWidth - tempWidth) {
                lineHeight += fontSize;
                wordsLength = 0;
            }
        }
    }

    render(x = 0, y = 0, option = {
        text: '',
        color: '#ff0000',
        fontSize: 20,
        lineWarpWidth: 200
    }) {
        let gl = this.gl;
        this._drawTexture(option.text, parseInt(option.fontSize, 10), parseInt(option.lineWarpWidth, 10));
        let textCanvasWidthOnWebGl = this.ctx.canvas.width * 2 / this.canvas.offsetWidth;
        let textCanvasHeightOnWebGl = this.ctx.canvas.height * 2 / this.canvas.offsetHeight;
        let verticesTexCoords = new Float32Array([
            x, y, 0, 1,
            x, y - textCanvasHeightOnWebGl, 0, 0,
            x + textCanvasWidthOnWebGl, y, 1, 1,
            x + textCanvasWidthOnWebGl, y - textCanvasHeightOnWebGl, 1, 0
        ]);
        let vertexTexCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.DYNAMIC_DRAW);
        const FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
        let a_Position = this.a_Position;
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
        gl.enableVertexAttribArray(a_Position);
        let a_TexCoord = this.a_TexCoord;
        gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
        gl.enableVertexAttribArray(a_TexCoord);
        gl.clearColor(1.0, 1.0, 1.0, 1.0);
        gl.enable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
        let canvasTexture = gl.createTexture();
        this._handleLoadedTexture(gl, canvasTexture, this.ctx.canvas, this.u_Sampler);
    }

    _handleLoadedTexture(gl, texture, textureCanvas, u_Sampler) {
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, texture);

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureCanvas); // This is the important line!
        gl.generateMipmap(gl.TEXTURE_2D);
        gl.uniform1i(u_Sampler, 0);
        // gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    }
}

export class TextCanvas {
    constructor(canvas) {
        this.canvas = canvas;
        this.context = this.canvas.getContext('2d');
    }
    renderOnece(x, y, option = {
        text: '',
        color: '#ff0000',
        fontSize: 20,
        lineWarpWidth: 200
    }) {
        this.context.font = `${option.fontSize}px monospace`;
        this.context.fillStyle = option.color || '#ff0000';
        let lineHeight = option.fontSize;
        let wordsLength = 0;
        for (let i = 0, length = option.text.length; i < length; i++) {
            let tempWidth = this.context.measureText(option.text.substring(i, i + 1)).width;
            this.context.fillText(option.text.substring(i, i + 1), wordsLength + x, lineHeight + y);
            wordsLength += tempWidth;
            if (wordsLength >= option.lineWarpWidth - tempWidth) {
                lineHeight += option.fontSize;
                wordsLength = 0;
            }
        }
    }

    render(repeatNum, option = {
        text: '',
        color: '#ff0000',
        fontSize: 20,
        lineWarpWidth: 200
    }) {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        for (let j = 0; j < repeatNum; j++) {
            this.renderOnece(Math.random() * this.canvas.width, Math.random() * this.canvas.height, option);
        }
    }

}